﻿# coding=utf-8
# encoding=utf8
# noinspection PyBroadException
import sys
import datetime
import os
import subprocess

import socketio
from flask import Flask, render_template, request, redirect, url_for, json, jsonify
from flask_cors import CORS
# from flask_wtf import FlaskForm
# from wtforms import StringField, SubmitField
# from wtforms.validators import DataRequired
# from flask_sqlalchemy import SQLAlchemy
from flask_socketio import SocketIO

from modes import Hosts, projects, DeployTask, Node, Logs, scTemp, middle, sysoptions
from gitclone import git
# from repo import GitRepository
from utils import Codezip, db
# from sqlalchemy import or_, and_
from sshclient import SSHProxy
# from flask_wtf import FlaskForm
from flask_bootstrap import Bootstrap
from Fomclass import addsysopt, addservers, addprojects, runshell

# import SocketIO

sys.setrecursionlimit(3000)
app = Flask(__name__)
app.secret_key = os.urandom(24)
db.init_app(app)
CORS(app)
bootstrap = Bootstrap(app)
app.config['SECRET_KEY'] = os.urandom(24)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:123456@127.0.0.1:3306/smartssh'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
date = datetime.datetime.now().strftime('%Y%m%d%H')
socketio = SocketIO()
socketio.init_app(app, cors_allowed_origins='*')
name_space = '/dcenter'


@app.route('/')
def hello_world():
    db.create_all()
    return render_template('server.html')


@app.route('/list')
def list():
    hostlist = Hosts.query.all()
    return render_template('server.html', hostlist=hostlist)


@app.route('/status/<int:id>', methods=['GET', 'POST'])
def status(id):
    if request.method == "GET":
        taskstatus = DeployTask.query.filter_by(id=id).first()  # 找到发布信息
        uid = taskstatus.uid
        nodeinfo = Node.query.filter_by(task=uid).all()
        statulist = []
        for row in nodeinfo:
            nostatus = {'key': str(row.id), "parent": str(row.parent), 'text': str(row.text), 'color': str(row.status)}
            statulist.append(nostatus)
        return jsonify(statulist)
    else:
        taskstatus = DeployTask.query.filter_by(id=id).first()  # 找到发布信息
        return json.dumps({'code': 'init', 'data': status})


@app.route('/add', methods=['GET', 'POST'])
def add():
    if request.method == 'GET':
        addhost = addservers()
        servergroup = sysoptions.query.filter_by(types='1').all()  # 查找服务器组信息
        for opt in servergroup:
            addhost.groups.choices.append((str(opt.id), str(opt.desc)))
        return render_template('addserver.html', addhost=addhost)
    else:
        dic1 = request.form
        print(dic1)
        savehost(id, dic1)
        return redirect(url_for('list'))


@app.route('/delhost/<int:id>', methods=['GET', 'POST'])
def delhost(id):
    try:
        hostinf = Hosts.query.filter_by(id=id).delete()
        db.session.commit()
    except Exception as e:
        db.session.rollback()
    return redirect(url_for('list'))


@app.route('/update/<int:id>', methods=['GET', 'POST'])
def update(id):
    hostinf = Hosts.query.filter_by(id=id).first()
    print("数据库值:%s" % hostinf.hostname)
    addhost = addservers()
    print("未修改前:%s" % addhost.hostname.default)
    # addhost.groups.choices.append((str(opt.id), str(opt.desc)))
    addhost.hostname.default = hostinf.hostname
    print("修改后:%s" % addhost.hostname.default)
    return render_template('addserver.html', addhost=addhost)


@app.route('/project', methods=['GET', 'POST'])
def project():
    if request.method == 'GET':
        pallroject = projects.query.all()
        return render_template('project.html', pallroject=pallroject)
    else:
        dic2 = request.form
        addproject(dic2)
        return redirect(url_for('project'))


@app.route('/delpro/<int:id>', methods=['GET', 'POST'])
def delpro(id):
    if request.method == 'GET':
        proinfo = projects.query.filter_by(id=id).delete()
        db.session.commit()
        return redirect(url_for('project'))


# 根据ID号获取项目的信息
@app.route('/task/<int:id>', methods=['GET', 'POST'])
def task(id):
    if request.method == 'GET':
        project = projects.query.filter_by(id=id).first()  # 根据项目ID拿到项目信息
        server = project.servers.split(',')
        # x = list.split(',')
        for s in server:
            print("server:%s" % s)
        tasklist = DeployTask.query.filter_by(project=project.project).all()  # 拿到此项目的发布信息
        return render_template('tasklist.html', tasklist=tasklist, project=project)
    else:
        return redirect(url_for('project'))


# 添加发布任务
@app.route('/addtask/<int:id>', methods=['GET', 'POST'])
def addtask(id):
    if request.method == 'GET':
        projectinfo = projects.query.filter_by(id=id).first()
        return render_template('addtask.html', projectinfo=projectinfo)
    else:
        projectinfo = projects.query.filter_by(id=id).first()
        project = projectinfo.project
        env = projectinfo.env
        dic3 = request.form
        date = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
        uid = project + '-' + env + '-' + dic3['tag'] + '-' + date
        addtaskdb(dic3, project, uid)
        return redirect(url_for('project'))


@app.route('/takeinfo/<int:id>', methods=['GET', 'POST'])
def takeinfo(id):
    if request.method == 'GET':
        taskinfo = DeployTask.query.filter_by(id=id).first()
        pro = taskinfo.project
        prinfo = projects.query.filter_by(project=pro).first()
        return render_template('bak/run.html', taskinfo=taskinfo, prinfo=prinfo)


@app.route('/push', methods=['GET'])
def push():
    push('jar-dev-master-20210308151905')
    # return render_template('test.html')
    return render_template('run.html')


@app.route('/addproject', methods=['GET', 'POST'])
def addproject():
    if request.method == 'GET':
        addpro = addprojects()
        hosts = Hosts.query.all()
        for host in hosts:
            addpro.servers.choices.append((str(host.hostname), str(host.hostname)))
        return render_template('addpro.html', addpro=addpro)
    else:
        slits = request.form.get('servers')
        dic2 = request.form
        serverlists = dict(request.form.lists())
        servers = (serverlists['servers'])
        endserver = (servers[-1])
        server = ''
        for host in servers:
            if host == endserver:
                server = server + host
            else:
                server = server + host + ','
        addpro = addproject(dic2, server)
        return redirect(url_for('project'))


@app.route('/system', methods=['GET', 'POST'])
def system():
    if request.method == 'GET':
        allopt = sysoptions.query.all()
        return render_template('system.html', allopt=allopt)
    else:
        # dic3 = request.form
        # project(dic3)
        # server = dic3['servers']
        # print(server)
        return redirect(url_for('project'))


@app.route('/addsystem', methods=['GET', 'POST'])
def addsystem():
    if request.method == 'GET':
        addopt = addsysopt()
        return render_template('addsystem.html', addopt=addopt)
    else:
        dic3 = request.form
        addsystem(dic3)
        return redirect(url_for('system'))


@app.route('/delsystem/<int:id>', methods=['GET', 'POST'])
def delsystem(id):
    if request.method == 'GET':
        sysopt = sysoptions.query.filter_by(id=id).delete()
        db.session.commit()
        return redirect(url_for('system'))


@app.route('/shell', methods=['GET', 'POST'])
def shell():
    if request.method == 'GET':
        shellrun = runshell()
        allhost = Hosts.query.all()
        for host in allhost:
            shellrun.servers.choices.append((str(host.hostname), str(host.hostname)))
        return render_template('shell.html', runshell=shellrun)


@app.route('/test1', methods=['GET', 'POST'])
def test1():
    return render_template('run.html')


@app.route('/run/<int:id>', methods=['GET', 'POST'])
def run(id):
    if request.method == 'GET':
        taskinfo = DeployTask.query.filter_by(id=id).first()
        taskinfo.status = "发布中"
        db.session.commit()
        projectinfo = projects.query.filter_by(project=taskinfo.project).first()  # 找到相对应的项目信息
        serverpath = '/root/update/' + date + '/' + '%s' % taskinfo.uid  # 服务器目录
        localpath = '/Users/dayang/PycharmProjects/Devops/codes/' + date
        print("localpath:%s" % localpath)
        uploadfile = localpath + '/' + taskinfo.uid + '.zip'  # 上传文件的约绝对地扯
        serverfile = serverpath + '/' + taskinfo.uid + '.zip'  # 上传文件的约绝对地扯
        scriptspath = serverpath + '/' + 'scripts'
        allhost = projects.query.filter_by(project=taskinfo.project).first()
        serverslist = allhost.servers.split(",")
        t = request.args.get('t')
        if t == "999":  # 生成初使化图表
            takuid = taskinfo.uid
            nodata = Node.query.filter(Node.task == takuid).delete()
            db.session.commit()
            startnode = Node(task=taskinfo.uid, text='开始', status='lightblue')
            db.session.add(startnode)
            db.session.commit()
            downloadnode = Node(task=taskinfo.uid, text='下载打包', status='lightblue', parent=startnode.id)
            db.session.add(downloadnode)
            db.session.commit()
            uploadnode = Node(task=taskinfo.uid, text='上传', status='lightblue', parent=downloadnode.id)
            db.session.add(uploadnode)
            db.session.commit()
            for host in serverslist:
                addhostnode = Node(task=taskinfo.uid, text=host, status='lightblue', parent=uploadnode.id)
                db.session.add(addhostnode)
                db.session.commit()
                before_deploy_node = Node(task=taskinfo.uid, text='发布前', status='lightblue', parent=addhostnode.id,
                                          servers=host)
                db.session.add(before_deploy_node)
                db.session.commit()
                deploy_node = Node(task=taskinfo.uid, text='发布', status='lightblue', parent=before_deploy_node.id)
                db.session.add(deploy_node)
                db.session.commit()
                resert_node = Node(task=taskinfo.uid, text='重启服务', status='lightblue', parent=deploy_node.id,
                                   servers=host)
                db.session.add(resert_node)
                db.session.commit()
                complete = Node(task=taskinfo.uid, text='完成', status='lightblue', servers=host, parent=resert_node.id)
                db.session.add(complete)
                db.session.commit()
            return "初使化完成"
        else:
            startnode = Node.query.filter_by(task=taskinfo.uid, text="开始").first()
            startnode.status = 'green'
            db.session.commit()
            print(taskinfo.uid)
            push(taskinfo.uid)
            downloadstatus = "green"
            try:
                git(projectinfo, taskinfo)
                if projectinfo.zip == "on":
                    dbsc = scTemp.query.filter_by(title='mvn').first()
                    mvnsc = os.path.join(localpath, taskinfo.uid, 'codes', "com.sh")
                    with open(mvnsc, mode='w', encoding='utf-8') as f:
                        f.write(dbsc.scripts)
                    try:
                        os.system(mvnsc)
                    except Exception as e:
                        print("编译失败")
            except Exception as e:
                downloadstatus = "red"
                downloadnode = Node.query.filter_by(task=taskinfo.uid, text="下载打包").first()
                downloadnode.status = downloadstatus
                db.session.commit()
            if downloadstatus == "red":
                push(taskinfo.uid)
                return "下载失败"
            else:
                uid = taskinfo.uid
                uploadnode = Node.query.filter_by(task=taskinfo.uid, text="上传").first()
                uploadnode.status = "green"
                db.session.commit()
                for host in serverslist:
                    upstatus = "green"
                    infohost = Hosts.query.filter_by(hostname=host).first()
                    try:
                        with SSHProxy(infohost.ipaddr, int(infohost.port), infohost.username,
                                      infohost.passwd) as ssh:
                            result = ssh.command("mkdir -p {0}".format(serverpath))  # 在服务器上创建文件夹
                            ssh.upload(uploadfile, serverfile)
                            result1 = ssh.command('unzip %s -d %s' % (serverfile, serverpath))
                            before_deploy_status = "green"
                            after_deploy_status = "green"
                            deploy_status = "green"
                            try:
                                if taskinfo.before_deploy_sc:  # 发布前的脚本
                                    scname = 'before_deploy_sc.sh'
                                    scpath = os.path.join(serverpath, 'scripts', scname)
                                    result = ssh.command("sh %s" % scpath)
                                    if result['code'] == 0:
                                        before_deploy_status = "green"
                                        push(uid)
                                    else:
                                        before_deploy_status = "red"
                                        if before_deploy_status == "red":
                                            push(uid)
                                            continue
                                try:
                                    Deplstatus = "green"
                                    servercode = os.path.join(serverpath, 'codes', '*')
                                    cmd = 'cp -Rf %s %s' % (servercode, projectinfo.path)
                                    copy = ssh.command(cmd)
                                    if copy['code'] == 0:
                                        deploy_status = "green"
                                        push(uid)
                                    else:
                                        deploy_status = "red"
                                        if deploy_status == "red":
                                            push(uid)
                                            continue
                                except Exception as e:
                                    deploy_status = "red"
                                    push(uid)
                                if taskinfo.after_deploy_sc:
                                    scname = 'after_deploy_sc.sh'
                                    scpath = os.path.join(serverpath, 'scripts', scname)
                                    result = ssh.command("sh %s" % scpath)
                                    if result['code'] == 0:
                                        after_deploy_status = "green"
                                        push(uid)
                                    else:
                                        after_deploy_status = "red"
                                        if after_deploy_status == "red":
                                            push(uid)
                                            continue
                                before_deploy_node = Node.query.filter_by(task=taskinfo.uid,
                                                                          text='发布前', servers=infohost.hostname).first()
                                deploy_node = Node.query.filter_by(task=taskinfo.uid,
                                                                   text='发布', servers=infohost.hostname).first()
                                deploy_node.status = Deplstatus
                                db.session.commit()
                                after_deploy_node = Node.query.filter_by(task=taskinfo.uid,
                                                                         text='重启服务', servers=infohost.hostname).first()
                                before_deploy_node.status = before_deploy_status
                                db.session.commit()
                                after_deploy_node.status = after_deploy_status
                                db.session.commit()
                                finish_node = Node.query.filter_by(task=taskinfo.uid,
                                                                   text='完成', servers=infohost.hostname).first()
                                finish_node.status = "green"
                                db.session.commit()
                                push(uid)
                            except Exception as e:
                                before_deploy_status = "red"
                                before_deploy = Node.query.filter_by(task=taskinfo.uid, servers=host,
                                                                     text="发布前").first()
                                before_deploy_status = before_deploy_status
                                db.session.commit()
                                push(uid)
                    except Exception as e:
                        upstatus = "red"
                        upnodeserver = Node.query.filter_by(task=taskinfo.uid, text=host).first()
                        upnodeserver.status = upstatus
                        db.session.commit()
                        push(uid)
                        continue

    return "ok"


def push(uid):
    event_name = 'dcenter'
    allinfo = Node.query.filter_by(task=uid).all()
    broad_ifo = []
    for nodeinfo in allinfo:
        broad_ifo.append(
            {'uid': nodeinfo.task, 'text': nodeinfo.text, 'status': nodeinfo.status,
             'parent': nodeinfo.parent, 'servers': nodeinfo.servers})
    socketio.emit(event_name, broad_ifo, broadcast=True, namespace=name_space)


def addtaskdb(dic3, project, uid):
    addtask1 = DeployTask(uid=uid, project=project, tag=dic3['tag'], versioninfo=dic3['versioninfo'],
                          after_download=dic3['after_download_sc'], before_download=dic3['before_download_sc'],
                          before_deploy_sc=dic3['before_deploy_sc'], after_deploy_sc=dic3['after_deploy_sc'])
    db.session.add(addtask1)
    db.session.commit()


def addproject(dic2, server):
    if 'zip' in dic2.keys():
        add1 = projects(project=dic2['project'], repo=dic2['Repo'], env=dic2['evn'],
                        path=dic2['path'], zip=dic2['zip'], servers=server)
        db.session.add(add1)
        db.session.commit()
    else:
        add1 = projects(project=dic2['project'], repo=dic2['Repo'], env=dic2['evn'],
                        path=dic2['path'], zip='off', servers=server)
        db.session.add(add1)
        db.session.commit()


def addsystem(dic3):
    if dic3['type'] == '4':
        addsc = scTemp(title=dic3['name'], scripts=dic3['value'], desc=dic3['desc'])
        db.session.add(addsc)
        db.session.commit()
    else:
        addsys = sysoptions(types=dic3['type'], values=dic3['value'], desc=dic3['desc'])
        db.session.add(addsys)
        db.session.commit()


def savehost(id, dic1):
    if id in dic1.keys():
        print(id)
        print(dic1)
    else:
        adddeivce = Hosts(hostname=dic1['hostname'], ipaddr=dic1['ipaddr'],
                          Groups=dic1['groups'], username=dic1['username'],
                          passwd=dic1['password'], port=int(dic1['sshport']),
                          Desc=dic1['Desc'])
        db.session.add(adddeivce)
        db.session.commit()
